import { PartFigure } from './PartFigure';
import { PPM } from './Canvas';
import {LCD12864} from '../model/parts/LCD12864';
import debouncer from '../util/debouncer';

let canvas_lcd12864: any = document.getElementById("canvas_lcd12864")
var ctx: any = canvas_lcd12864.getContext("2d")
ctx.fillStyle = "#555"

const CanvasPixelSize = 5

export default class LCD12864Figure extends PartFigure {

    private body: raphaeljs.Element
    private headerStuds: raphaeljs.Set
    private screen: raphaeljs.Element
    private view: raphaeljs.Element

    public drawing: boolean = true
    public brushSize: 1|3|5 = 3

    private repaintDebouncer: any

    protected createChild() {
        
        this.repaintDebouncer = debouncer(()=>{
            this.view.attr("src", canvas_lcd12864.toDataURL())
        })

        this.headerStuds = this.canvas.paper.set()
        for(let i=0;i<6; i++) {
            this.headerStuds.push( this.canvas.paper.path([
                ["M", i*8*PPM+1.6*PPM, 1.6*PPM] ,
                ["L", i*8*PPM+1.6*PPM, 0] ,
                ["L", i*8*PPM+6.4*PPM, 0] ,
                ["L", i*8*PPM+6.4*PPM, 1.6*PPM] ,
                ["z"]
            ]).attr({ fill: '#eee' }) )
        }

        this.body = this.canvas.paper.path([
            ["M", 0, 1.6*PPM] ,
            ["L", 48*PPM, 1.6*PPM] ,
            ["L", 48*PPM, 48*PPM+1.6*PPM] ,
            ["L", 0, 48*PPM+1.6*PPM] ,
            ["z"]
        ]).attr({ fill: '#eee' })

        // port
        this.createPort(this.part.studs[0][0], 0, 1.6*PPM,)
        this.createPort(this.part.studs[0][1], 8*PPM, 1.6*PPM)
        this.createPort(this.part.studs[0][2], 16*PPM, 1.6*PPM)
        this.createPort(this.part.studs[0][3], 24*PPM, 1.6*PPM)
        this.createPort(this.part.studs[0][4], 32*PPM, 1.6*PPM)
        this.createPort(this.part.studs[0][5], 40*PPM, 1.6*PPM)
        this.createPort(this.part.studs[1][0], 0, 41.6*PPM)
        this.createPort(this.part.studs[1][1], 8*PPM, 41.6*PPM)
        this.createPort(this.part.studs[1][2], 16*PPM, 41.6*PPM)
        this.createPort(this.part.studs[1][3], 24*PPM, 41.6*PPM)
        this.createPort(this.part.studs[1][4], 32*PPM, 41.6*PPM)
        this.createPort(this.part.studs[1][5], 40*PPM, 41.6*PPM)

        // screen 
        this.screen = this.canvas.paper.path([
            ["M", 5*PPM, 10.6*PPM] ,
            ["L", 43*PPM, 10.6*PPM] ,
            ["L", 43*PPM, 40.6*PPM] ,
            ["L", 5*PPM, 40.6*PPM] ,
            ["z"]
        ]).attr({ fill: '#e5efe7' })

        // view port 
        this.view = this.canvas.paper.image( canvas_lcd12864.toDataURL(), 56, 96,  128, 64 )
        // console.log(this.view)
        

        let matrix = (this.part as LCD12864).matrix 
        matrix[0][0] = 1
        matrix[0][127] = 1
        matrix[63][0] = 1
        matrix[63][127] = 1
        this.drawPreview()


        this.allElements.push(this.body)
        this.allElements.push(this.headerStuds)
        this.allElements.push(this.screen)
        this.allElements.push(this.view)

        this.draggableElements.push(this.body)
        this.draggableElements.push(this.screen)
        this.draggableElements.push(this.view)

        this.growSet.push(this.body)
        this.growSet.push(this.headerStuds)
        
        this.selector.setup(this.body)
        this.selector.setup(this.headerStuds)
        this.selector.setup(this.screen)
        this.selector.setup(this.view)

        this.initDrawing()
    }

    public drawPreview() {

        // 清屏
        canvas_lcd12864.width = canvas_lcd12864.width

        let matrix = (this.part as LCD12864).matrix 
        for(let r=0;r<matrix.length;r++) {
            for(let c=0;c<matrix[r].length;c++) {
                if(matrix[r][c]) {
                    this.drawPixel(c, r)
                }
            }
        }
        
        this.repaintPreview()
    }

    public drawPixel(x:number, y:number) {
        if(x<0 || x>127 || y<0 || y>63)
            return
        ctx.rect(x*CanvasPixelSize, y*CanvasPixelSize, CanvasPixelSize-1, CanvasPixelSize-1)
        ctx.fill()
    }

    public brush(x:number, y:number) {
        let h = (this.brushSize-1)/2
        let lft = x - h
        let top = y - h
        
        for(let dx=0; dx<this.brushSize; dx++) {
            for(let dy=0; dy<this.brushSize; dy++) {
                this.drawPixel(lft+dx, top+dy)
            }
        }
    }
    
    public repaintPreview() {
        this.repaintDebouncer()
    }

    protected onDragging(x: number, y: number, e: any) {
        if(e.target==this.view.node && this.drawing) {
            return false
        }
        return true
    }

    private initDrawing() {

        let brushing = false
        let lastX: any = undefined, lastY: any = undefined
        
        let draw = (x:number, y:number) => {
            let {x:bx, y:by} = this.view.getBBox()
            let {x: cx, y: cy} = this.canvas.coords(x, y)
            cx = Math.round(cx)
            cy = Math.round(cy)
            let px = (cx - bx)
            let py = (cy - by)

            this.brush(px, py)

            // 连线
            if(lastX!=undefined && lastY!=undefined) {
                let dx = px - lastX
                let dy = py - lastY
                let dis = Math.sqrt(dx*dx + dy*dy)
                let midDots = Math.ceil( dis / this.brushSize ) - 1
                if(midDots>0) {
                    let segx = dx/(midDots+1)
                    let segy = dy/(midDots+1)
                    for(let i=1;i<=midDots;i++) {
                        let dotX = Math.round(lastX + i*segx)
                        let dotY = Math.round(lastY + i*segy)
                        this.brush(dotX, dotY)
                    }
                }
            }

            this.repaintPreview()

            lastX = px
            lastY = py
        }

        
        this.view.touchstart(()=>{
            if(!this.drawing) return
            lastX = undefined
            lastY = undefined
            brushing = true
        })
        this.view.touchmove((e: any)=>{
            if(!this.drawing)
                return 
            // 单指滑动
            if(e.targetTouches.length==1)
                draw(e.targetTouches[0].clientX, e.targetTouches[0].clientY)
        })

        this.view.mousedown(()=>{
            if(!this.drawing) return
            lastX = undefined
            lastY = undefined
            brushing = true
        })
        this.view.mousemove((e: MouseEvent, x:number, y:number)=>{
            if(brushing)
                draw(x, y)
        })
        this.view.mouseup(()=>{ brushing = false })
        this.view.mouseout(()=>{ brushing = false })
    }

}